home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 026-050 / scopedisk28 / getfil / getfile.c < prev    next >
C/C++ Source or Header  |  1995-03-18  |  16KB  |  660 lines

  1. /* getfile.c */
  2.  
  3. /*    This file contains a general-purpose 'requester' that
  4. will prompt the user for a filename input.
  5.     The program actually uses a window instead of a 'Requester'
  6. for greater flexibility. It will take control of your window's
  7. IDCMP Port when called.
  8.  
  9.     This code borrows from several sources, but has been EXTENSIVELY
  10. revised (read improved, cleaned up, made readable).
  11.  
  12.     Advantages of this file requester:
  13.  
  14.     1.    NO 'Wrong Diskette?' MESSAGE!!!!!!!!
  15.         Since The System prompts for a volume if it can't find it,
  16.         why rub it in the user's face?  If the user selects a path
  17.         that does not work, this code will try the previous path
  18.         again.  If that is also bad, it goes to DF0:, since
  19.         everyone has one of those.
  20.  
  21.     2.    The 'OK' gadget can have any text you want in it up to
  22.         six characters.  Try '  OK  ', ' LOAD ', ' SAVE '
  23.         and the like.
  24.  
  25.     3.    Hitting 'Return' while editing the path searches that path.
  26.  
  27.     4.    Hitting 'Return' while editing the file name is same as
  28.         hitting the 'OK' gadget.
  29.  
  30.     5.    Standard device gadgets for df0:, df1:, and dh0:
  31.  
  32.     6.    Easy to read, more comments, and variables with names that
  33.         have meaning (as opposed to ones like 'kludge', 'oops' etc.)
  34.  
  35.     7.    Which means easy to modify.  You can add pattern filters and
  36.         extra device gadgets (like ram:, vd0:) quite easily.
  37.         If you do add gadgets, make sure to account for the 'OK'
  38.         gadget text, which currently goes into DrWIText9.IText
  39.  
  40.     Dave Arendash
  41.     Escape Velocity, Inc.
  42.     405 Rancho Arroyo  #264
  43.     Fremont, CA  94536
  44. */
  45.  
  46. #include "standard.h"
  47. #include "getfile.h"
  48.  
  49.  
  50. /* extern struct IntuiMessage *GetMsg(); */
  51. extern char *BrowseDir();
  52. extern char *StartBrowsing();
  53.  
  54. static struct FileLock *DirPtr = NULL;
  55. static struct FileInfoBlock *dir_info;
  56. static struct Window   *ParentWin;        /* Parent Window. */
  57.  
  58. static struct TextAttr DirFont =
  59. {
  60.     "topaz.font",
  61.     TOPAZ_EIGHTY,FS_NORMAL,FPF_ROMFONT
  62. };
  63.  
  64. #include "filereq.h"
  65.  
  66. static struct direntry
  67. {
  68.     struct direntry *next;
  69.     BOOL isfile;
  70.     char text[DSIZE+2];
  71. };
  72.  
  73. static struct direntry *FirstEntry;
  74. static struct direntry *NextEntry;
  75. static struct dirhead
  76. {
  77.     struct direntry *next;
  78. };
  79. static struct dirhead ListHead;
  80. static long   CurEntry, TotalEntries;
  81. static BOOL   more;
  82. static struct Window    *ReqWindow = NULL;        /* Requester window   */
  83. static struct RastPort    *ReqRastPort;
  84.  
  85. /* Requester "Hailing" prompt */
  86. static struct IntuiText TopIText = {2,2,JAM1,10,11,NULL, NULL ,NULL};
  87.  
  88. static struct IntuiText DirIText =
  89. {
  90.     0,1,JAM2,0,1,
  91.     &DirFont,
  92.     (UBYTE *)"(dir) ",
  93.     NULL
  94. };
  95.  
  96. static struct IntuiText names[DENTS] =
  97. {
  98.    /* File name list */
  99.    {2,1,JAM2,48,1,NULL,NULL, NULL},
  100.    {2,1,JAM2,48,1,NULL,NULL, NULL},
  101.    {2,1,JAM2,48,1,NULL,NULL, NULL},
  102.    {2,1,JAM2,48,1,NULL,NULL, NULL},
  103.    {2,1,JAM2,48,1,NULL,NULL, NULL}
  104. };
  105.  
  106. /* Open a requester "Window" */
  107.  
  108. static struct NewWindow NewFiles =
  109. {
  110.    160, 30, REQWIDTH,REQHEIGHT, BCOL,FCOL, NULL, /* Fill in AFTER opening ... */
  111.    SMART_REFRESH | ACTIVATE | RMBTRAP | WINDOWDRAG,
  112.    &DrWGadgetList1, NULL, NULL, NULL,
  113.    NULL, REQWIDTH, REQHEIGHT, REQWIDTH, REQHEIGHT, WBENCHSCREEN
  114. };
  115. static struct IntuiText Note_IText = {0,1,JAM2, 5,20,NULL,NULL, NULL};
  116. static struct IntuiText OK_IText = {0,1,JAM2, 5,3,NULL,"  OK", NULL};
  117.  
  118. TEXT    *pathtxt;
  119. char    *retval;
  120. char    *path;
  121. char    *name;
  122. char    *pddef, *pddir, orgname[MAXSTRINGSIZE], orgpath[MAXSTRINGSIZE];
  123. char    temppath[MAXSTRINGSIZE], tempname[MAXSTRINGSIZE];
  124. BOOL    OKtoGo;
  125. BOOL    dir_flag;
  126.  
  127. IMPORT struct Library    *IntuitionBase;
  128.  
  129. /*  get_fname (window, screen, hail, ddef, ddir, txt);
  130.  
  131.    Displays a window/requester that
  132.  gets a file name for device, directory, default file
  133.  
  134.    Calling args:
  135.      window:    Window making the request
  136.      screen:    Screen, if NULL assummed workbench
  137.      hail:        Text at top of requester (may be used as a prompt)
  138.      ddef:        Input default file-name. Has NO DRIVE OR PATH
  139.      ddir:        Directory of file, may be null
  140.      txt:        text for OK button
  141.  
  142.      If the user hits 'Cancel', these won't be
  143.      overwritten.  If he hits 'OK', they will be overwritten
  144.      with the path and filenames which appear in the string
  145.      gadgets at that time.  Returns 0 if unsuccessful for any
  146.      reason.
  147. */
  148.  
  149. get_fname (CallWin, screen, hail, ddef, ddir, txt)
  150.    struct Window *CallWin;    /* Calling Window */
  151.    struct Screen *screen;    /* screen .... if null assume workbench */
  152.    UBYTE    *hail;        /* Hailing prompt */
  153.    char        *ddef;        /* default probable file-name */
  154.    char        *ddir;        /* default directory in which to search */
  155.    char        *txt;        /* text for OK button, if NULL, uses 'OK' */
  156. {
  157.     register struct IntuiMessage *imes; /* Wait for message in here*/
  158.     register struct Gadget    *igad;    /* gadget identifier */
  159.     register long        i, j, class;
  160.  
  161.     orgname[0] = orgpath[0] = tempname[0] = temppath[0] = 0;
  162.  
  163.     /* copy originals to orgname and orgpath for editing */
  164.     strcpy (orgname, ddef);
  165.     strcpy (orgpath, ddir);
  166.     path = orgpath;
  167.     name = orgname;
  168.     pddef = ddef;
  169.     pddir = ddir;
  170.  
  171.     if (!(ParentWin = CallWin))
  172.         return (NULL);
  173.  
  174.     /* set text for OK button */
  175.     if (txt)
  176.         strcpy (DrWIText9.IText, txt);
  177.     else
  178.         strcpy (DrWIText9.IText, "  OK");
  179.  
  180.     /* Set default file name */
  181.     DrWFileNameGadSInfo.Buffer = name;
  182.  
  183.     /* Set default device name */
  184.     DrWPathGadSInfo.Buffer = path;
  185.  
  186.     /* clear name structures */
  187.     for (i=0; i < DENTS; i++)
  188.     {
  189.         names[i].IText = "";
  190.         names[i].NextText = NULL;
  191.     };
  192.  
  193.     NewFiles.Title = ParentWin->Title;
  194.  
  195.     /* get memory for file info operations */
  196.     if (!(dir_info = AllocMem ((long)sizeof(struct FileInfoBlock), 0L)))
  197.         return (NULL);
  198.  
  199.     /* if user supplied a screen, use it */
  200.     if (screen)
  201.     {
  202.         NewFiles.Type = CUSTOMSCREEN;
  203.         NewFiles.Screen = screen;
  204.         NewFiles.LeftEdge = (screen->Width - REQWIDTH) >> 1;
  205.         NewFiles.TopEdge = (screen->Height - REQHEIGHT) >> 1;
  206.     }
  207.  
  208.     /* allocate a heap and open the window */
  209.     if (!(FirstEntry = (struct direntry *)AllocMem ((long)DBUFSIZ,0L)) ||
  210.             !(ReqWindow = (struct Window *)OpenWindow (&NewFiles)))
  211.      {
  212.          if (FirstEntry)
  213.             FreeMem (FirstEntry,(long)DBUFSIZ);
  214.  
  215. /*        notify (ReqWindow,"Can't Open Requester..."); */
  216.         FreeMem (dir_info, (long)sizeof (struct FileInfoBlock));
  217.         return (NULL);
  218.      }
  219.  
  220.     /* Set up directory */
  221.     Path();
  222.  
  223.     /* This optional line will activate a string gadget */
  224.     if (IntuitionBase->lib_Version > 32)
  225.         ActivateGadget (&DrWFileNameGad,ReqWindow,0L);
  226.  
  227.     ReqRastPort = ReqWindow->RPort;
  228.  
  229.     /* set up the message port */
  230.     ReqWindow->UserPort = ParentWin->UserPort;
  231.     ModifyIDCMP (ReqWindow, (long)MOUSEBUTTONS | (long)GADGETDOWN | 
  232.             (long)GADGETUP | (long)MOUSEMOVE);
  233.  
  234.     /* paint background color of requester */
  235.     SetAPen (ReqRastPort,1L);
  236.     RectFill (ReqRastPort,4L,10L,(long)(NewFiles.Width-5),
  237.                 (long)(NewFiles.Height-4));
  238.  
  239.     /* put hailing text on screen */
  240.     TopIText.IText = hail;
  241.     TopIText.LeftEdge = (REQWIDTH - IntuiTextLength(&TopIText)) >> 1L;
  242.     PrintIText (ReqRastPort, &TopIText, 0L, 0L);
  243.  
  244.     /* put all gadgets on screen */
  245.     RefreshGadgets (&DrWOKGad, ReqWindow, 0L);
  246.  
  247.     /* assume all ok */
  248.     OKtoGo = 1;
  249.  
  250.     /* do until OK, Cancel, or bad error */
  251.     while (OKtoGo)
  252.     {
  253.         while (!(imes = GetMsg (ReqWindow->UserPort)))
  254.         {
  255.             /* if displayed directory list needs updating... */
  256.             if (dir_flag)
  257.             {
  258.                 /* determine index of first displayed name */
  259.                 i = (long)(TotalEntries - DENTS) *
  260.                     (j = (long)DrWDirPropGadSInfo.VertPot) /
  261.                     (long)MAXBODY;
  262.                 if (i > (TotalEntries - DENTS))
  263.                     i = TotalEntries - DENTS;
  264.                 if (i < 0L)
  265.                     i = 0L;
  266.                 CurEntry = i;
  267.                 /* display what we have to date */
  268.                 DispDir();
  269.                 dir_flag = 0;
  270.             }
  271.  
  272.             /* if more entries to be read, read them; otherwise
  273.                wait for user to do something */
  274.             if (more)
  275.             {
  276.                 /* read them, or say why we can't */
  277.                 if (pathtxt = (char *)BrowseDir())
  278.                     notify (ReqWindow, pathtxt);
  279.  
  280.                 if (TotalEntries <= DENTS)
  281.                     dir_flag = TRUE;
  282.             }
  283.             else
  284.                 WaitPort (ReqWindow->UserPort);
  285.         }
  286.  
  287.         /* interpret user interaction message */
  288.         igad = (struct Gadget *)imes->IAddress;
  289.         class = imes->Class;
  290.         ReplyMsg (imes);
  291.  
  292.         switch (class)
  293.         {
  294.             case MOUSEMOVE:
  295.                 /* user is scrolling, flag a re-display */
  296.                 dir_flag = TRUE;
  297.  
  298.             case GADGETUP:
  299.             case GADGETDOWN:
  300.                 /* a gadget activated */
  301.                 HandleEvent (igad);
  302.                 break;
  303.         }
  304.     }
  305.  
  306.     /* clean up memory */
  307.     FreeMem (FirstEntry, (long)DBUFSIZ);
  308.     FreeMem (dir_info, (long)sizeof (struct FileInfoBlock));
  309.  
  310.     /* clean up after disk access */
  311.     free_DirPtr ();
  312.  
  313.     CloseWindowSafely (ReqWindow);
  314.     return (1);
  315. }
  316.  
  317. /* used when user clicks on a directory entry in the displayed list */
  318. DirEnt (gad)
  319. struct Gadget *gad;    /* one of the DENTS gadgets containing names */
  320. {
  321.     short i, dirent;
  322.  
  323.     dirent = gad->GadgetID - (short)DIR_ENT1;
  324.  
  325.     /* Replace file or directory name */
  326.     pathtxt = names[dirent].IText;
  327.  
  328.     /* if filename */
  329.     if (names[dirent].NextText == NULL)
  330.     {
  331.         /* update the file name editing gadget */
  332.         RemoveGadget (ReqWindow,&DrWFileNameGad);
  333.         for (i = 0; i < DSIZE; i++)
  334.             name[i] = *pathtxt++;
  335.         AddGadget (ReqWindow, &DrWFileNameGad, -1L);
  336.         RefreshGadgets (&DrWFileNameGad, ReqWindow, 0L);
  337.     }
  338.     else
  339.     {
  340.         /* else dir name */
  341.         /* update the path name editing gadget */
  342.         RemoveGadget (ReqWindow, &DrWPathGad);
  343.         pathcat (path, pathtxt);
  344.         *DrWFileNameGad.SpecialInfo.Buffer = 0;
  345.         AddGadget (ReqWindow, &DrWPathGad, -1L);
  346.         RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
  347.     }
  348.     /* update displayed list as needed */
  349.     Path();
  350. }
  351.  
  352. /* various gadgets hit (selected), replace paths with these defaults */
  353. DF0Hit ()
  354. {
  355.     strcpy (path, "df0:");
  356.     RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
  357.     Path();
  358. }
  359.  
  360. DF1Hit ()
  361. {
  362.     strcpy (path, "df1:");
  363.     RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
  364.     Path();
  365. }
  366.  
  367. DH0Hit ()
  368. {
  369.     strcpy (path, "dh0:");
  370.     RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
  371.     Path();
  372. }
  373.  
  374. /* read the disk for entries on this path */
  375. /* called when user presses 'Return' when editing path name, and whenever
  376.    we want to read a directory */
  377. Path ()
  378. {
  379.     /* try the chosen path */
  380.     if (!StartBrowsing (path))
  381.         /* good new directory, clear the file name */
  382.         *DrWFileNameGad.SpecialInfo.Buffer = 0;
  383.     else
  384.     {
  385.         /* something wrong with new directory, restore old */
  386.         strcpy (name, tempname);
  387.         strcpy (path, temppath);
  388.         RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
  389.  
  390.         /* this old directory may also now be invalid
  391.             (if user has removed the disk, for instance.
  392.            The System has alread asked him about this by now */
  393.         if (!StartBrowsing (path))
  394.         {
  395.             /* if all else fails, EVERYONE HAS A DRIVE DF0:! */
  396.             strcpy (path, "df0:");
  397.             RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
  398.             StartBrowsing (path);
  399.         }
  400.     }
  401.     dir_flag = TRUE;
  402. }
  403.  
  404. /* called when the directory proportional gadget is moved */
  405. DirProp ()
  406. {
  407.     /* user scrolling, flag for re-display */
  408.     dir_flag = TRUE;
  409. }
  410.  
  411. /* called when user presses 'Return' when editing file name */
  412. FileName ()
  413. {
  414.     /* Name gadget, 'Return' pressed assumes same as hitting OK gadget */
  415.     retval = name;
  416.     OKHit();
  417. }
  418.  
  419. OKHit()
  420. {
  421.     /* OK gadget */
  422.     retval = name;
  423.     /* return the edited name and path */
  424.     strcpy (pddef, orgname);
  425.     strcpy (pddir, orgpath);
  426.     /* flag to exit requester */
  427.     CancelHit();
  428. }
  429.  
  430. CancelHit()
  431. {
  432.     /* flag to exit requester */
  433.     OKtoGo = FALSE;
  434. }
  435.  
  436. /* clean up after disk access */
  437. static free_DirPtr()
  438. {
  439.     if (DirPtr)
  440.     {
  441.         UnLock (DirPtr);
  442.         DirPtr = NULL;
  443.     }
  444. }
  445.  
  446. /*
  447.  StartBrowsing ()
  448.    Initialize the file info block for directory access.  Null return
  449.    is good, else return is a pointer to an error string      */
  450.  
  451. static char *StartBrowsing (subdir)
  452. char *subdir;
  453. {
  454.     more = FALSE;
  455.     CurEntry = TotalEntries = 0;
  456.  
  457.     NextEntry = FirstEntry;      /* Allocate from here   */
  458.     ListHead.next = NULL;          /* Clear the list     */
  459.  
  460.     free_DirPtr();   /* Unlock any old lock */
  461.  
  462.     /* lock this directory so it can't be deleted while we're here */
  463.     DirPtr = (struct FileLock *)Lock (subdir, (ULONG)ACCESS_READ);
  464.  
  465.     /* if file not found, or couldn't read directory, or is a file... */
  466.     if (!DirPtr || !Examine (DirPtr, dir_info) ||
  467.         (dir_info->fib_DirEntryType < 0L ))
  468.     {
  469.         dir_flag = 1;
  470.         return ("Could not read disk");
  471.     }
  472.  
  473.     /* got a good path, remember where it is */
  474.     strcpy (tempname, name);
  475.     strcpy (temppath, path);
  476.     more = TRUE;
  477.     return (BrowseDir());
  478. }
  479.  
  480. /* read directory entries and put them in the list to be displayed */
  481. static char *BrowseDir()
  482. {
  483.     register struct direntry *TmpDir = NextEntry;
  484.     register struct direntry   *ThisPtr = (struct direntry *)&ListHead;
  485.     register struct direntry   *NextPtr;
  486.     register TEXT   *tmpstr;
  487.     register long   i;
  488.  
  489.     if (!more)
  490.         return (NULL);
  491.  
  492.     /* if there is any entries we haven't read yet, read another... */
  493.     if (ExNext (DirPtr, dir_info))
  494.     {
  495.         /* run out of heap space? */
  496.         if ((ULONG)TmpDir >=
  497.                 ((ULONG)FirstEntry + (ULONG)DBUFSIZ -
  498.             (ULONG)sizeof (struct direntry)))
  499.         {
  500.             more = FALSE;
  501.             return ("Directory Truncated");
  502.         }
  503.  
  504.         /*******************************************************
  505.  
  506.            Here you can add a file/directory filter and/or
  507.            pattern matching filter(s). You will probably also
  508.            want to add this pattern format string to the parameter
  509.            list passed to get_fname()
  510.  
  511.         *******************************************************/
  512.  
  513.         /* filename text string is at &TmpDir->text[0] */
  514.  
  515.         /* set file type flag */
  516.         TmpDir->isfile = (dir_info->fib_DirEntryType < 0L);
  517.  
  518.         /* copy the name from the file info block just read */
  519.         tmpstr = &TmpDir->text[0];
  520.         for (i=0; i < FCHARS; i++)
  521.             if (!(*tmpstr++ = dir_info->fib_FileName[i]))
  522.                 break;
  523.         *tmpstr = 0;
  524.  
  525.         /* move down in heap, long word align */
  526.         i = (long)tmpstr;
  527.         NextEntry = (struct direntry *)((i+5L) & ~3L);
  528.  
  529.         /* bump up number of entries read, insert new entry into
  530.            linked list of entries, based on alphabetic order,
  531.            scanning from head of list */
  532.         for (i = TotalEntries++; i >= 0; i--)
  533.         {
  534.             if (!(NextPtr = ThisPtr->next))
  535.                 break;
  536.             if (is_alpha_lower (TmpDir, NextPtr))
  537.                 break;
  538.             ThisPtr = NextPtr;
  539.         }
  540.         /* actual list insertion (ThisPtr-->NextPtr becomes
  541.                       ThisPtr-->TmpDir-->NextPtr) */
  542.         TmpDir->next = NextPtr;
  543.         ThisPtr->next = TmpDir;
  544.         return (NULL);
  545.      }
  546.      else
  547.         return (IoErr() == ERROR_NO_MORE_ENTRIES) ?
  548.             (char *)(more = 0L) : "Error Reading Directory";
  549. }
  550.  
  551. /* dedicated alphabetizing function for BrowseDir()
  552. /* returns TRUE if first string comes before second string alphabetically,
  553.    and files always come before directories */
  554.  
  555. static is_alpha_lower (EntA, EntB)
  556.    struct direntry *EntA, *EntB;
  557. {
  558.     register struct direntry *PtrA = EntA;
  559.     register TEXT *psA,*psB, a,b;
  560.  
  561.     /* if both are files or directories... */
  562.     if (PtrA->isfile == EntB->isfile)
  563.     {
  564.         /* scan strings to determine order */
  565.         psA = &PtrA->text[0];
  566.         psB = &EntB->text[0];
  567.         while (a = *psA++)
  568.         {
  569.             if (a > (b = *psB++))
  570.                 return (FALSE);
  571.             else if (a < b)
  572.                 break;
  573.         }
  574.         return (TRUE);
  575.     }
  576.     /* if it got this far, one string is file, other is dir */
  577.     return (PtrA->isfile);
  578. }   
  579.  
  580. /* Display directory listing */
  581. static DispDir()
  582. {
  583.     register long   i,new;
  584.     register long   x,y;
  585.     register struct direntry *dir_entry = (struct direntry *)&ListHead;
  586.  
  587.     /* scan down list to current entry pointer */
  588.     new = CurEntry;
  589.     for (i = 0; i < new; i++)
  590.         dir_entry = dir_entry->next;
  591.  
  592.     y = 20L;
  593.     for (i = 0; i < DENTS; i++)
  594.     {
  595.         y += (x = 10);
  596.         names[i].NextText = NULL;
  597.         names[i].IText = "";
  598.         names[i].LeftEdge = 0;
  599.  
  600.         /* if entry is in window... */
  601.          if ((new+i) < TotalEntries)
  602.          {
  603.              dir_entry = dir_entry->next;
  604.  
  605.             /* print text to window depending on entry type */
  606.              names[i].IText = &dir_entry->text[0];
  607.              if (dir_entry->isfile)
  608.                 PrintIText (ReqRastPort, &names[i], 10L, y);
  609.             else
  610.             {
  611.                 /* if entry is a directory, put the '(dir)'
  612.                     in front of it */
  613.                 names[i].LeftEdge = 48;
  614.                 PrintIText (ReqRastPort, &DirIText, 10L, y);
  615.                 PrintIText (ReqRastPort, &names[i], 10L, y);
  616.                 names[i].NextText = &DirIText;
  617.             }
  618.             x = ReqRastPort->cp_x;
  619.         }
  620.         if (x < FILLWIDTH+10)
  621.             RectFill (ReqRastPort,x,y,(long)(FILLWIDTH+10),
  622.                     (long)(y+8L));
  623.     }
  624. }
  625.  
  626. /*
  627.  pathcat()
  628.    Combines dir, plus name into dir   */
  629.  
  630. pathcat (dir, file_name)
  631.    char *dir, *file_name;
  632. {
  633.     register char   *pdst = dir;
  634.     register char   *psrc = file_name;
  635.     register char   c = ':';
  636.  
  637.     /* scan to end of 'dir' string */
  638.     while (*pdst)
  639.         c = *pdst++;
  640.  
  641.     /* if it wasn't a volume spec, put a subdirectory slash on it */
  642.     if (c != ':')
  643.         *pdst++ = '/';
  644.  
  645.     /* append name */
  646.     while (*pdst++ = *psrc++);
  647. }
  648.  
  649. /* notify (win, txt) */
  650. /*   Prompts for Yes/No response */
  651.  
  652. notify (win, txt)
  653. struct Window *win;
  654. char *txt;
  655. {
  656.     Note_IText.IText = txt;
  657.     AutoRequest (win, &Note_IText, 0L, &OK_IText, 0L, 0L,
  658.         (long)(IntuiTextLength (&Note_IText) + 50L), 70L);
  659. }
  660.